package com.yifeng.repo.micro.service.server.engine.configure;

import com.gomcarter.frameworks.base.common.AssertUtils;
import com.yifeng.repo.micro.service.server.engine.conf.NacosConf;
import com.yifeng.repo.micro.service.server.engine.core.JsonHandlerMethodArgumentResolver;
import com.yifeng.repo.micro.service.server.engine.core.JsonRequestFilter;
import com.yifeng.repo.micro.service.server.engine.listener.AppLifeCycleListener;
import com.yifeng.repo.micro.service.server.engine.listener.AppRequestListener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.ServletRequestListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Created by daibing on 2023/3/15.
 */
@Slf4j
@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)
@EnableConfigurationProperties(ServerEngineRequestProperties.class)
@ConditionalOnProperty(prefix = "yfcloud.micro.service.engine.request", name = "enabled", matchIfMissing = true)
public class ServerEngineRequestConfiguration {
    @Resource
    private ServerEngineRequestProperties properties;

    @Resource
    private RequestMappingHandlerAdapter requestMappingHandlerAdapter;

    @Bean(initMethod = "init")
    public NacosConf nacosConf() {
        return new NacosConf();
    }

    @Bean
    public AppLifeCycleListener appLifeCycleListener() {
        return new AppLifeCycleListener();
    }

    @Bean
    public ServletListenerRegistrationBean<ServletRequestListener> appRequestListener() {
        ServletListenerRegistrationBean<ServletRequestListener> registration = new ServletListenerRegistrationBean<>();
        registration.setListener(new AppRequestListener(Arrays.asList(properties.getCopyHeaderPrefixes())));
        return registration;
    }

    @Bean
    public FilterRegistrationBean<Filter> jsonRequestFilter() {
        FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
        registration.setDispatcherTypes(DispatcherType.REQUEST);
        registration.setFilter(new JsonRequestFilter(properties.getExcludeUri()));
        registration.addUrlPatterns(properties.getUrlPatterns());
        registration.setName(JsonRequestFilter.class.getSimpleName());
        registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE);
        return registration;
    }

    @PostConstruct
    public void init() {
        this.addArgumentResolvers();
    }

    private void addArgumentResolvers() {
        // 未启用
        if (!properties.isJsonHandlerMethodArgumentResolverEnable()) {
            return;
        }

        // 2. 获取框架定义的参数解析集合(不可变集合)，并且找出需要的分解器
        List<HandlerMethodArgumentResolver> argumentResolvers = requestMappingHandlerAdapter.getArgumentResolvers();
        AssertUtils.notNull(argumentResolvers, "argumentResolverList must not be null!");

        // 3. 将自定义Json分解器插入第一个，并且重新设置处理器
        List<HandlerMethodArgumentResolver> engineArgumentResolvers = new ArrayList<>(argumentResolvers.size() + 1);
        engineArgumentResolvers.add(new JsonHandlerMethodArgumentResolver(argumentResolvers));
        engineArgumentResolvers.addAll(argumentResolvers);
        requestMappingHandlerAdapter.setArgumentResolvers(engineArgumentResolvers);
    }
}